<mat-tab-header #tabHeader
                [selectedIndex]="selectedIndex || 0"
                [disableRipple]="disableRipple"
                [disablePagination]="disablePagination"
                [aria-label]="ariaLabel"
                [aria-labelledby]="ariaLabelledby"
                (indexFocused)="_focusChanged($event)"
                (selectFocusedIndex)="selectedIndex = $event">

  @for (tab of _tabs; track tab) {
    <div class="mdc-tab mat-mdc-tab mat-focus-indicator"
        #tabNode
        role="tab"
        matTabLabelWrapper
        cdkMonitorElementFocus
        [id]="_getTabLabelId(tab, $index)"
        [attr.tabIndex]="_getTabIndex($index)"
        [attr.aria-posinset]="$index + 1"
        [attr.aria-setsize]="_tabs.length"
        [attr.aria-controls]="_getTabContentId($index)"
        [attr.aria-selected]="selectedIndex === $index"
        [attr.aria-label]="tab.ariaLabel || null"
        [attr.aria-labelledby]="(!tab.ariaLabel && tab.ariaLabelledby) ? tab.ariaLabelledby : null"
        [class.mdc-tab--active]="selectedIndex === $index"
        [class]="tab.labelClass"
        [disabled]="tab.disabled"
        [fitInkBarToContent]="fitInkBarToContent"
        (click)="_handleClick(tab, tabHeader, $index)"
        (cdkFocusChange)="_tabFocusChanged($event, $index)">
      <span class="mdc-tab__ripple"></span>

      <!-- Needs to be a separate element, because we can't put
          `overflow: hidden` on tab due to the ink bar. -->
      <div
        class="mat-mdc-tab-ripple"
        mat-ripple
        [matRippleTrigger]="tabNode"
        [matRippleDisabled]="tab.disabled || disableRipple"></div>

      <span class="mdc-tab__content">
        <span class="mdc-tab__text-label">
          <!--
            If there is a label template, use it, otherwise fall back to the text label.
            Note that we don't have indentation around the text label, because it adds
            whitespace around the text which breaks some internal tests.
          -->
          @if (tab.templateLabel) {
            <ng-template [cdkPortalOutlet]="tab.templateLabel"></ng-template>
          } @else {{{tab.textLabel}}}
        </span>
      </span>
    </div>
  }
</mat-tab-header>

<!--
  We need to project the content somewhere to avoid hydration errors. Some observations:
  1. This is only necessary on the server.
  2. We get a hydration error if there aren't any nodes after the `ng-content`.
  3. We get a hydration error if `ng-content` is wrapped in another element.
-->
@if (_isServer) {
  <ng-content/>
}

<div
  class="mat-mdc-tab-body-wrapper"
  [class._mat-animation-noopable]="_animationsDisabled()"
  #tabBodyWrapper>
  @for (tab of _tabs; track tab;) {
    <mat-tab-body role="tabpanel"
                 [id]="_getTabContentId($index)"
                 [attr.tabindex]="(contentTabIndex != null && selectedIndex === $index) ? contentTabIndex : null"
                 [attr.aria-labelledby]="_getTabLabelId(tab, $index)"
                 [attr.aria-hidden]="selectedIndex !== $index"
                 [class]="tab.bodyClass"
                 [content]="tab.content!"
                 [position]="tab.position!"
                 [animationDuration]="animationDuration"
                 [preserveContent]="preserveContent"
                 (_onCentered)="_removeTabBodyWrapperHeight()"
                 (_onCentering)="_setTabBodyWrapperHeight($event)"
                 (_beforeCentering)="_bodyCentered($event)"/>
  }
</div>
